package cn.b.sky.mes.pp.service.impl;

import cn.b.sky.common.exception.ImeException;
import cn.b.sky.common.model.Page;
import cn.b.sky.i18n.utils.LocaleResourceBundle;
import cn.b.sky.mes.cm.enums.OperationType;
import cn.b.sky.mes.cm.model.ProcessComponent;
import cn.b.sky.mes.cm.model.ProcessOperation;
import cn.b.sky.mes.cm.service.ProcessService;
import cn.b.sky.mes.mm.constants.MmConstant;
import cn.b.sky.mes.mm.model.MoveType;
import cn.b.sky.mes.mm.service.InventoryService;
import cn.b.sky.mes.mm.service.MoveTypeService;
import cn.b.sky.mes.pp.dao.ProductionControlDao;
import cn.b.sky.mes.pp.dao.ProductionOrderConfirmDao;
import cn.b.sky.mes.pp.dao.ProductionOrderDao;
import cn.b.sky.mes.pp.enums.OrderStatusCode;
import cn.b.sky.mes.pp.enums.PorderStatusCode;
import cn.b.sky.mes.pp.enums.ProductionControlStatusCode;
import cn.b.sky.mes.pp.model.*;
import cn.b.sky.mes.pp.model.condition.ProductionOperationCondition;
import cn.b.sky.mes.pp.service.ProductOrderService;
import cn.b.sky.mes.pp.service.ProductionOrderConfirmService;
import cn.b.sky.mes.pp.service.ProductionOrderService;
import cn.b.sky.mes.pp.service.RequirementStrategyService;
import cn.b.sky.mes.pp.utils.NumberUtils;
import cn.b.sky.shop.activiti.service.impl.EvunProcessEngine;
import cn.b.sky.user.SecurityContextUtil;
import cn.b.sky.user.service.ParameterService;
import cn.b.sky.user.service.model.ParameterEntity;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

@Service("productionOrderConfirmService")
public class ProductionOrderConfirmServiceImpl implements ProductionOrderConfirmService {

    // 日志对象
    protected static final Logger LOGGER = LoggerFactory.getLogger(ProductionOrderConfirmServiceImpl.class);

    @Resource
    ProductionOrderConfirmDao productionOrderConfirmDao;

    @Resource
    private EvunProcessEngine skyProcessEngine;
    @Resource
    ProductOrderService productOrderService;

    @Resource
    ProductionOrderService productionOrderService;

    @Resource
    ProductionControlDao productionControlDao;

    @Resource
    ProductionOrderDao productionOrderDao;

    @Resource
    MoveTypeService moveTypeService;

    @Resource
    ProcessService processService;

    @Resource
    InventoryService inventoryService;

    @Resource
    RequirementStrategyService requirementStrategyService;

    @Resource
    ParameterService parameterService;

    private static final String PULL_STRATEGY_ENABLE = "PULL_STRATEGY_ENABLE";

    private static final String CONFIRMBYLASTOPERA = "CONFIRMBYLASTOPERA";

    @Override
    public List<ProductionOperation> selectProductionOperationByPC(String siteCode, String productionControlNum) {
        return productionOrderConfirmDao.selectProductionOperationByPC(siteCode, productionControlNum);
    }

    /**
     * 通过主键查询
     *
     * @param id
     * @return
     */
    @Override
    public ProductionOperation getProductionOperationById(Long id) {
        if (null == id) {
            return null;
        }
        return productionOrderConfirmDao.getProductionOperationByPk(id);
    }

    /**
     * 查询需要报工的订单工序
     *
     * @param condition
     * @return
     */
    @Override
    public Page getProductionOperationByCondition(ProductionOperationCondition condition) {
        if (condition == null) {
            condition = new ProductionOperationCondition();
        }
        long count = productionOrderConfirmDao.countProductionOperation(condition);
        if (count > 0) {
            condition.setTotalCount(count);
            condition.setData(productionOrderConfirmDao.listProductionOperation(condition));
        } else {
            condition.setTotalCount(0);
            condition.setData(Lists.newArrayList());
        }

        return condition;
    }

    @Override
    @Transactional
    public void doConfirmProduction(List<ProductionConfirm> confirmList) {
        /*
         * insertConfirmDetail(confirmList);
         * updatePOConfirmOperation(confirmList);
         * updateProductionControl(confirmList);
         * updateProductionOrder(confirmList);
         */
        for (ProductionConfirm confirm : confirmList) {
            ProductionOperation oper = productionOrderConfirmDao.selectProductionOperation(confirm.getSiteCode(),
                    confirm.getProductionControlNum(), confirm.getProcessOperationId());
            double canConfirmQty = oper.getPlannedQuantity() - oper.getCompletedQuantity();
            //检查报工数量是否超限
            if (confirm.getCompletedQuantity().doubleValue() > canConfirmQty) {
           /*     String message = LocaleResourceBundle.getCommonResourceLabel(confirm.getSiteCode(),
                        SecurityContextUtil.getLanguageCode(), "confirmQtyOver.M",
                        new String[]{NumberUtils.subZeroAndDot(Double.toString(canConfirmQty))});*/
                throw ImeException.newException("confirmQtyOver.M", new String[]{NumberUtils.subZeroAndDot(Double.toString(canConfirmQty))});
            }
        }
        insertConfirmDetail(confirmList);
        updatePOConfirmOperation(confirmList);
        updateProductionControl(confirmList);
        updateProductionOrder(confirmList);
       /* Map<String, Object> map = new HashMap<String, Object>();
        String tenantId = confirmList.get(0).getSiteCode();

        // 变量生产订单
        map.put("confirmList", confirmList);
        //变量工厂
        map.put("tenantId", tenantId);
        skyProcessEngine.startProcessByKeyAndTenantId(map, "confirmProductionOrder", tenantId);
*/
    }

    /**
     * <strong>Title : insertConfirmDetail<br>
     * </strong> <strong>Description : </strong>新增报工明细<br>
     * <strong>Create on : 2015-10-12 下午05:07:07<br>
     * </strong>
     * <p>
     *
     * @param confirmList void
     * @throws
     * @author zhaoxin01<br>
     * @version <strong>v1.0.0</strong><br>
     * <br>
     * <strong>修改历史:</strong><br>
     * 修改人 | 修改日期 | 修改描述<br>
     * -------------------------------------------<br>
     * <br>
     * <br>
     */
    @Override
    public void insertConfirmDetail(List<ProductionConfirm> confirmList) {
        for (ProductionConfirm po : confirmList) {
            po.setCreateDateTime(new Date());
            po.setModifyDateTime(new Date());
            productionOrderConfirmDao.insertProductionConfirm(po);
        }
    }

    /**
     * <strong>Title : updatePOConfirmOperation<br>
     * </strong> <strong>Description : </strong>更新确认点信息<br>
     * <strong>Create on : 2015-10-12 下午05:08:11<br>
     * </strong>
     * <p>
     *
     * @param confirmList void
     * @throws
     * @author zhaoxin01<br>
     * @version <strong>v1.0.0</strong><br>
     * <br>
     * <strong>修改历史:</strong><br>
     * 修改人 | 修改日期 | 修改描述<br>
     * -------------------------------------------<br>
     * <br>
     * <br>
     */
    @Override
    public void updatePOConfirmOperation(List<ProductionConfirm> confirmList) {
        // 按工序合并
        Map<String, ProductionOperation> cList = new HashMap<String, ProductionOperation>();
        for (ProductionConfirm po : confirmList) {
            String key = po.getSiteCode() + po.getProductionControlNum() + po.getProcessOperationId().toString();
            if (cList.containsKey(key)) {
                cList.get(key).setCompletedQuantity(cList.get(key).getCompletedQuantity() + po.getCompletedQuantity());
                cList.get(key).setScrappedQuantity(cList.get(key).getScrappedQuantity() + po.getScrappedQuantity());
            } else {
                ProductionOperation opera = productionOrderConfirmDao.selectProductionOperation(po.getSiteCode(),
                        po.getProductionControlNum(), po.getProcessOperationId());
                ProductionOperation info = new ProductionOperation();
                info.setSiteCode(po.getSiteCode());
                info.setProductionControlNum(po.getProductionControlNum());
                info.setProcessOperationId(po.getProcessOperationId());
                info.setCompletedQuantity(opera.getCompletedQuantity() + po.getCompletedQuantity());
                info.setScrappedQuantity(opera.getScrappedQuantity() + po.getScrappedQuantity());
                info.setModifyUser(po.getModifyUser());
                info.setModifyDateTime(new Date());
                cList.put(info.getSiteCode() + info.getProductionControlNum() + Long.toString(info.getProcessOperationId()),
                        info);
            }
        }

        // 更新确认点信息
        for (String key : cList.keySet()) {
            ProductionOperation val = cList.get(key);
            productionOrderConfirmDao.updateProductionOperation(val);
        }
    }

    /**
     * <strong>Title : updateProductionControl<br>
     * </strong> <strong>Description : </strong>更新订单明细<br>
     * <strong>Create on : 2015-10-12 下午05:15:21<br>
     * </strong>
     * <p>
     *
     * @param confirmList void
     * @throws
     * @author zhaoxin01<br>
     * @version <strong>v1.0.0</strong><br>
     * <br>
     * <strong>修改历史:</strong><br>
     * 修改人 | 修改日期 | 修改描述<br>
     * -------------------------------------------<br>
     * <br>
     * <br>
     */
    @Override
    public void updateProductionControl(List<ProductionConfirm> confirmList) {
        Map<String, ProductionControl> pList = new HashMap<String, ProductionControl>();
        for (ProductionConfirm po : confirmList) {
            String key = po.getSiteCode() + po.getProductionControlNum();
            if (pList.containsKey(key)) {
                continue;
            }
            //查询对应的生产管理号
            ProductionControl dinfo = productionControlDao.selectProductionControl(po.getSiteCode(),
                    po.getProductionControlNum());

            ProductionControl info = productionControlDao.selectProductionControlCompletedQuantity(po.getSiteCode(),
                    po.getProductionControlNum());
            info.setSiteCode(po.getSiteCode());
            info.setProductionControlNum(po.getProductionControlNum());
            boolean confirmBylast = false;
            try {
                ParameterEntity entity = parameterService.getParameterEntityByCode(CONFIRMBYLASTOPERA, po.getSiteCode());
                confirmBylast = !StringUtils.isEmpty(entity.getDefaultValue())
                        && Integer.valueOf(entity.getDefaultValue()).intValue() == 1;
            } catch (Exception e) {
                LOGGER.error("{}", e);
            }
            if (confirmBylast) {
                //只按最后一道确认点工序的完成数量做为生产管理号的完成数量
                int completedQty = productionOrderConfirmDao.selectLastOperationCompletedQuantity(po.getSiteCode(),
                        po.getProductionControlNum());
                info.setCompletedQuantity(Double.parseDouble(Integer.toString(completedQty)));
            }
            if (dinfo.getPlannedQuantity().doubleValue() == info.getCompletedQuantity().doubleValue()) {
                info.setStatuseCode(ProductionControlStatusCode.COMPLETE.getValue());
                if (!dinfo.getStatuseCode().equals(ProductionControlStatusCode.COMPLETE.getValue())) {
                    info.setActualendDateTime(new Date());
                }
            } else {
                info.setStatuseCode(ProductionControlStatusCode.SUBMIT.getValue());
            }
            info.setModifyUser(po.getModifyUser());
            info.setModifyDateTime(new Date());
            pList.put(po.getSiteCode() + po.getProductionControlNum(), info);
        }
        for (String key : pList.keySet()) {
            ProductionControl val = pList.get(key);
            productionControlDao.updateProductionControl(val);
        }
    }

    /**
     * <strong>Title : updateProductionOrder<br>
     * </strong> <strong>Description : </strong>更新生产订单<br>
     * <strong>Create on : 2015-10-12 下午05:15:44<br>
     * </strong>
     * <p>
     *
     * @param confirmList void
     * @throws
     * @author zhaoxin01<br>
     * @version <strong>v1.0.0</strong><br>
     * <br>
     * <strong>修改历史:</strong><br>
     * 修改人 | 修改日期 | 修改描述<br>
     * -------------------------------------------<br>
     * <br>
     * <br>
     */
    @Override
    public void updateProductionOrder(List<ProductionConfirm> confirmList) {
        Map<String, ProductionOrder> pList = new HashMap<String, ProductionOrder>();
        for (ProductionConfirm po : confirmList) {
            if (StringUtils.isBlank(po.getProductionOrderNum())) {
                ProductionControl control = productionControlDao.selectProductionControl(po.getSiteCode(), po.getProductionControlNum());
                po.setProductionOrderNum(control.getProductionOrderNum());
            }
            String key = po.getProductionOrderNum().toString();
            if (pList.containsKey(key)) {
                continue;
            }
            ProductionOrder info = productionOrderDao.selectOrderCompletedQuantity(po.getSiteCode(),
                    po.getProductionOrderNum());
            //生产管理号报工数量小于0则不用更新生产订单信息
            if(info.getCompletedQuantity() <= 0) {
                continue;
            }
            info.setSiteCode(po.getSiteCode());
            info.setProductionOrderNum(po.getProductionOrderNum());
            ProductionOrder dinfo = productionOrderDao.selectProductionOrdersByPk(po.getSiteCode(),
                    po.getProductionOrderNum());
            info.setMaterialCode(dinfo.getMaterialCode());
            //设置产品订单的物料
            ProductOrder porder = productOrderService.getProductOrderByPk(po.getSiteCode(), dinfo.getProductOrderNum());
            info.setProductMaterialCode(porder.getMaterialCode());
            info.setProductOrderNum(dinfo.getProductOrderNum());
            if (dinfo.getPlannedQuantity().doubleValue() == info.getCompletedQuantity().doubleValue()) {
                info.setStatuseCode(OrderStatusCode.COMPLETE.getValue());
                if (!dinfo.getStatuseCode().equals(OrderStatusCode.COMPLETE.getValue())) {
                    info.setActualendDateTime(new Date());
                }
            }
            info.setModifyUser(po.getModifyUser());
            info.setModifyDateTime(new Date());
            pList.put(info.getProductionOrderNum(), info);
        }
        for (String key : pList.keySet()) {
            ProductionOrder val = pList.get(key);
            productionOrderDao.updateProductionOrder(val);
            //生产订单如果是产品订单的物料，进行产品订单进度更新
            if (val.getMaterialCode().equals(val.getProductMaterialCode())) {
                ProductOrder pOrder = new ProductOrder();
                pOrder.setSiteCode(val.getSiteCode());
                pOrder.setProductOrderNum(val.getProductOrderNum());
                pOrder.setCompletedQuantity(val.getCompletedQuantity());
                pOrder.setScrappedQuantity(val.getScrappedQuantity());
                if (OrderStatusCode.COMPLETE.getValue().equals(val.getStatuseCode())) {
                    pOrder.setActualendDateTime(val.getActualendDateTime());
                    pOrder.setStatuseCode(PorderStatusCode.COMPLETE.getValue());
                }
                pOrder.setModifyUser(val.getModifyUser());
                pOrder.setModifyDateTime(new Date());
                productOrderService.modifyNoCreateProductionOrder(pOrder);
            }
        }
    }

    @Override
    public void buckleMaterial(List<ProductionConfirm> confirmList) {
        String tenantId = confirmList.get(0).getSiteCode();
        MoveType moveType = moveTypeService.getMoveType(tenantId, MmConstant.MOVETYPECODE);
        if (moveType == null || StringUtils.isBlank(moveType.getMoveTypeCode())) {
            throw ImeException.newException("notExstisBackflush.C", MmConstant.MOVETYPECODE.split(","));
        }
        for (ProductionConfirm confirm : confirmList) {
            ProductionControl control = productionControlDao.selectProductionControl(confirm.getSiteCode(),
                    confirm.getProductionControlNum());
            List<ProcessOperation> operations = processService.getProcessOperationByProcessCode(control.getSiteCode(),
                    control.getProcessCode(), control.getProcessRev());
            // 前一个确认点
            int prevConfirmIndex = -1;
            // 当前确认点
            int curConfirmIndex = 0;
            if (operations != null && operations.size() > 0) {
                for (int i = 0; i < operations.size(); i++) {
                    ProcessOperation operation = operations.get(i);
                    if (operation.getId().intValue() == confirm.getProcessOperationId().intValue()) {
                        curConfirmIndex = i;
                        break;
                    } else if (null != operation.getConfirmFlag() && operation.getConfirmFlag().intValue() == 1) {
                        prevConfirmIndex = i;
                    }
                }
            }
            //报工确认点到前一个报工点之前的每一道的生产工序进行扣料
            for (int i = prevConfirmIndex + 1; i <= curConfirmIndex; i++) {
                ProcessOperation processOperation = operations.get(i);
                if (OperationType.PRODUCTION.getValue().equals(processOperation.getOperationTypeEcode())) {
                    List<ProcessComponent> components = processService
                            .getProcessComponentByProcessOperation(processOperation.getId());
                    //扣料
                    todoBuckleMaterial(confirm, components);
                }
            }
            //生产基于安全库存策略的物料需求
            boolean isPull = false;
            try {
                ParameterEntity entity = parameterService.getParameterEntityByCode(PULL_STRATEGY_ENABLE, confirm.getSiteCode());
                isPull = !StringUtils.isEmpty(entity.getDefaultValue())
                        && Integer.valueOf(entity.getDefaultValue()).intValue() == 1;
            } catch (Exception e) {
                String message = LocaleResourceBundle.getCommonResourceLabel(confirm.getSiteCode(),
                        SecurityContextUtil.getLanguageCode(), "pullStrategyEnable.M");
                throw new RuntimeException(message);
            }
            if (isPull) {
                requirementStrategyService.createSafetyInventoryRequirements(confirm);
            }
        }
    }

    private void todoBuckleMaterial(ProductionConfirm confirm, List<ProcessComponent> components) {
        if (components != null && components.size() > 0) {
            double quantity = confirm.getCompletedQuantity() + confirm.getRepairQuantity() + confirm.getScrappedQuantity();
            for (ProcessComponent component : components) {
                inventoryService.productBuckleMaterial(confirm.getSiteCode(), confirm.getWorkUnitCode(),
                        confirm.getWorkCenterCode(), quantity * component.getQuantity().doubleValue(),
                        component.getComponentCode());
            }
        }
    }

}
